//*******************************************************************/
// ee_hqxaa, Hilda vs.c    for VS1003
// with reference to Zhang Qi Bo
// with reference to VS1003 datasheet
//******************************************************************/
// serial protocol for Serial Command Interface (SCI)
// one byte instr (0x03 read; 0x02 write)
// one byte address
// two byte data
//******************************************************************/
// serial protocol for Serial Data Interface (SDI)
// XDCS active low , for byte synchronization
// VS1003 has 32 bytes buffer
// so what we are going to do is read one SD sector of 512 byte
// loop: write 32 bytes to VS, check DREQ to be high
//******************************************************************/
// XTALI = 12.288MHz

#define F_CPU 7372800UL

#include <avr/io.h>
#include <util/delay.h>
#include "VS.h"


//=========================================
// for debug only
//=========================================


#define DEBUGLED1_CON() DDRA|=_BV(PA0)
#define DEBUGLED1_ON()  PORTA|=_BV(PA0)
#define DEBUGLED1_OFF() PORTA&=~_BV(PA0)

#define DEBUGLED2_CON() DDRA|=_BV(PA1)
#define DEBUGLED2_ON()  PORTA|=_BV(PA1)
#define DEBUGLED2_OFF() PORTA&=~_BV(PA1)

#define DEBUGLED3_CON() DDRA|=_BV(PA2)
#define DEBUGLED3_ON()  PORTA|=_BV(PA2)
#define DEBUGLED3_OFF() PORTA&=~_BV(PA2)

#define DEBUGLED4_CON() DDRA|=_BV(PA3)
#define DEBUGLED4_ON()  PORTA|=_BV(PA3)
#define DEBUGLED4_OFF() PORTA&=~_BV(PA3)

#define DEBUGLED5_CON() DDRA|=_BV(PA4)
#define DEBUGLED5_ON()  PORTA|=_BV(PA4)
#define DEBUGLED5_OFF() PORTA&=~_BV(PA4)

#define DEBUGLED6_CON() DDRA|=_BV(PA5)
#define DEBUGLED6_ON()  PORTA|=_BV(PA5)
#define DEBUGLED6_OFF() PORTA&=~_BV(PA5)

#define DEBUGLED7_CON() DDRA|=_BV(PA6)
#define DEBUGLED7_ON()  PORTA|=_BV(PA6)
#define DEBUGLED7_OFF() PORTA&=~_BV(PA6)

#define DEBUGLED8_CON() DDRA|=_BV(PA7)
#define DEBUGLED8_ON()  PORTA|=_BV(PA7)
#define DEBUGLED8_OFF() PORTA&=~_BV(PA7)


//=========================================
// for debug only
//=========================================




// config SPI speed High or low
void VS_SPI_Low(void)
{
	SPCR =   _BV(SPE)|_BV(MSTR)|_BV(SPR1)|_BV(SPR0);
	SPSR &= ~_BV(SPI2X);
}
void VS_SPI_High(void)
{
	SPCR =  _BV(SPE)|_BV(MSTR);
	SPSR |= _BV(SPI2X);
}
void VS_delay(uint n){while(n--)asm("nop");}




uchar VS_WriteByte(unsigned char CH){
	SPDR = CH;
	while(!(SPSR & _BV(SPIF)));							//wait for transmit
	return SPDR;
}
uchar VS_ReadByte(void){
	SPDR = 0xff;
	while(!(SPSR & _BV(SPIF)));
	return SPDR;
}




//for VS SPI protocal
//instruction opcode for read: 0b00000011;
//instruction opcode for write 0b00000010;
void VS_WriteCMD(uchar addr, uint dat){ //16bit int
	VS_XDCS_H();
	VS_XCS_L();
		VS_WriteByte(0x02);								//write 16 bits
		VS_WriteByte(addr);
		VS_WriteByte(dat>>8);							//MSB first
		VS_WriteByte(dat);
	VS_XCS_H();
}

uint VS_ReadCMD(uchar addr){
	uint temp;
	VS_XDCS_H();
	VS_XCS_L();
		VS_WriteByte(0x03);								//read 16 bits
		VS_WriteByte(addr);
		temp = VS_ReadByte();
		temp<<=8;										//MSB first
		temp += VS_ReadByte();
	VS_XCS_H();
	return temp;
}

void VS_WriteDAT(uchar dat){
	VS_XCS_H();
	VS_XDCS_L();										// disassert CS and assert DCS to enable data transfer
		VS_WriteByte(dat);
	VS_XDCS_H();

}






//-----------------------------------------
//--VS hardware reset and software reset---
//-----------------------------------------


void VS_SoftReset(void){
	//activate bit 2 in SCI_MODE
	VS_WriteCMD(0x00,0x0804);
	//after software reset, wait at least 1.35ms for DREQ to reset
	VS_delay(0xffff);
}



void spi_init(void)
{
	SPI_DDR	|= _BV(SPI_SCK) | _BV(SPI_MOSI);
	SPI_DDR &= ~_BV(SPI_MISO);

	SPCR &= (~_BV(SPIE)) & (~_BV(DORD)) & (~_BV(SPR1));
	SPCR |= _BV(SPE) | _BV(MSTR) | _BV(SPR0) | _BV(SPR1);
	SPSR = 0;
	SPSR &= ~_BV(SPI2X);

	DDRA = 0xff;

}





uchar VS_ini(void){

	spi_init();
	PORT_INI();

	VS_DDR &= ~_BV(VS_DREQ);							//pull down DREQ
	VS_XCS_H();
	VS_XDCS_H();

	VS_XRESET_L();										// hardware reset
	_delay_ms(30);
	_delay_ms(30);

	VS_XCS_H();
	VS_XDCS_H();
	VS_XRESET_H();

//	VS_SPI_Low();

			while(!(VS_PIN & _BV(VS_DREQ))){
				;
			}													//wait for DREQ to be high

			VS_WriteCMD(0,0x0804);								// software reset

			while(!(VS_PIN & _BV(VS_DREQ))){
				;
			}

			VS_WriteCMD(0x03,0x9800);							// clk = 3* XTALI

			VS_WriteCMD(0x05,0xac45);							// default frequency 44.1Kbps

			VS_WriteCMD(0x02,0x0055);							// bass enhance

			VS_WriteCMD(0xB, 0x2020);							// set default volume

			VS_WriteByte(0xff);
			VS_WriteByte(0xff);
			VS_WriteByte(0xff);
			VS_WriteByte(0xff);									// dummy bytes to start communication

	VS_SPI_High();

	return 0;
}


